
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Derm.Render
{
	/// <summary>
	/// Generic bounding volume interface.
	/// </summary>
	public interface IBoundVolume
	{
		/// <summary>
		/// Check whether a three-dimensional position relies in this IBoundVolume.
		/// </summary>
		/// <param name="p">
		/// A <see cref="Vertex3f"/> that specifies the position.
		/// </param>
		/// <returns>
		/// It returns a boolean value indicating whether the position <paramref name="p"/> is inside this IBoundVolume.
		/// </returns>
		bool IsWithinVolume(Vertex3f p);
	}

	/// <summary>
	/// Bounding box.
	/// </summary>
	public class BoundBox : IBoundVolume
	{
		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		public BoundBox()
		{
		
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="o"></param>
		/// <param name="w"></param>
		/// <param name="h"></param>
		/// <param name="d"></param>
		public BoundBox(Vertex3f o, float w, float h, float d)
		{
			float w2 = w/2.0f, h2 = h/2.0f, d2 = d/2.0f;

			mBounds[0] = new Vertex3f(o.x-w2, o.y-h2, o.z-d2);
			mBounds[1] = new Vertex3f(o.x+w2, o.y+h2, o.z+d2);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="min"></param>
		/// <param name="max"></param>
		public BoundBox(Vertex3f min, Vertex3f max)
		{
			mBounds[0] = min;
			mBounds[1] = max;
		}

		#endregion

		#region Box Definition

		/// <summary>
		/// 
		/// </summary>
		/// <param name="vbo"></param>
		public void ComputeBounds(ArrayBufferObject<Vertex3f> vbo)
		{
			
		}

		/// <summary>
		/// Box vertices bounds.
		/// </summary>
		private Vertex3f[] mBounds = new Vertex3f[2] {
			new Vertex3f(float.MaxValue, float.MaxValue, float.MaxValue),
			new Vertex3f(float.MinValue, float.MinValue, float.MinValue),
		};

		#endregion

		#region BoundVolume Implementation

		/// <summary>
		/// Check whether a three-dimensional position relies in this BoundBox.
		/// </summary>
		/// <param name="p">
		/// A <see cref="Vertex3f"/> that specifies the position.
		/// </param>
		/// <returns>
		/// It returns a boolean value indicating whether the position <paramref name="p"/> is inside this BoundBox.
		/// </returns>
		public virtual bool IsWithinVolume(Vertex3f p)
		{
			return (
				(p.x >= mBounds[0].x) && (p.x <= mBounds[1].x) &&
				(p.y >= mBounds[0].y) && (p.y <= mBounds[1].y) &&
				(p.z >= mBounds[0].z) && (p.z <= mBounds[1].z)
				);
		}

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class BoundBoxAligned : BoundBox
	{
		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		/// <param name="min"></param>
		/// <param name="max"></param>
		public BoundBoxAligned(Vertex3f min, Vertex3f max) : base(min, max)
		{
		
		}

		#endregion

		#region BoundVolume Implementation

		/// <summary>
		/// Check whether a three-dimensional position relies in this BoundBox.
		/// </summary>
		/// <param name="p">
		/// A <see cref="Vertex3f"/> that specifies the position.
		/// </param>
		/// <returns>
		/// It returns a boolean value indicating whether the position <paramref name="p"/> is inside this BoundBox.
		/// </returns>
		public override bool IsWithinVolume(Vertex3f p)
		{
			return (false);
		}

		#endregion
	}

	/// <summary>
	/// 
	/// </summary>
	public class BoundSphere : IBoundVolume
	{
		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		public BoundSphere()
		{
			
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="p"></param>
		/// <param name="r"></param>
		public BoundSphere(Vertex3f p, float r)
		{
			Debug.Assert(r >= 0.0f);

			mCenter = p;
			mRadius = r;
		}

		#endregion

		#region Sphere Definition

		/// <summary>
		/// 
		/// </summary>
		public Vertex3f Center
		{
			get { return (mCenter); }
			set { mCenter = value; }
		}

		/// <summary>
		/// 
		/// </summary>
		public float Radius
		{
			get { return (mRadius); }
			set { mRadius = value; }
		}

		/// <summary>
		/// Bounding sphere center position.
		/// </summary>
		private Vertex3f mCenter = new Vertex3f();
		/// <summary>
		/// Bounding sphere radius.
		/// </summary>
		private float mRadius = 0.0f;

		#endregion

		#region BoundVolume Implementation

		/// <summary>
		/// Check whether a three-dimensional position relies in this BoundSphere.
		/// </summary>
		/// <param name="p">
		/// A <see cref="Vertex3f"/> that specifies the position.
		/// </param>
		/// <returns>
		/// It returns a boolean value indicating whether the position <paramref name="p"/> is inside this BoundSphere.
		/// </returns>
		public virtual bool IsWithinVolume(Vertex3f p)
		{
			return ((mCenter-p).Module() < mRadius);
		}

		#endregion
	}
}
